package com.kfm.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.kfm.common.domain.entity.Menu;
import com.kfm.common.domain.entity.User;
import com.kfm.common.domain.model.LoginUser;
import com.kfm.common.util.Constant;
import com.kfm.common.util.JwtUtils;
import com.kfm.system.mapper.MenuMapper;
import com.kfm.system.mapper.RoleMapper;
import com.kfm.system.mapper.UserMapper;
import com.kfm.system.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private RedisTemplate<String, List<String>> redisTemplate;


    @Override
    public int deleteByPrimaryKey(Integer id) {
        return userMapper.deleteByPrimaryKey(id);
    }

    @Override
    public int insertSelective(User record) {
        // 密码加密
        record.setPassword(new BCryptPasswordEncoder().encode(record.getPassword()));
        return userMapper.insertSelective(record);
    }

    @Override
    public User selectByPrimaryKey(Integer id) {
        return userMapper.selectByPrimaryKey(id);
    }

    @Override
    public int updateByPrimaryKeySelective(User record) {
        return userMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public int updateByPrimaryKey(User record) {
        return userMapper.updateByPrimaryKey(record);
    }

    @Override
    public List<User> selectAll() {
        return userMapper.selectAll();
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.selectByUsername(username);
        if (ObjectUtils.isEmpty(user)) {
            log.error("用户名不存在");
            throw new UsernameNotFoundException("用户名不存在");
        }
        // 查询用户的权限和角色
        List<String> permissions = redisTemplate.opsForValue().get(Constant.PERMISSION_LIST + user.getId());
        List<String> roles = redisTemplate.opsForValue().get(Constant.ROLE_LIST + user.getId());
        if (ObjectUtils.isEmpty(permissions) || permissions.isEmpty() || ObjectUtils.isEmpty(roles) || roles.isEmpty()) {
            roles = roleMapper.selectByUid(user.getId())
                    .stream()
                    .map(role -> "ROLE_" + role.getRoleIdentifier())
                    .toList();
            permissions = menuMapper.selectByUserId(user.getId())
                    .stream()
                    .map(Menu::getPermissionIdentifier).toList();
            redisTemplate.opsForValue().set(Constant.PERMISSION_LIST + user.getId(), permissions, 1, TimeUnit.DAYS);
            redisTemplate.opsForValue().set(Constant.ROLE_LIST + user.getId(), roles, 1, TimeUnit.DAYS);
        }
        // 将权限和角色放入 authorities
        Set<SimpleGrantedAuthority> authorities = new HashSet<>();
        roles.forEach(role -> authorities.add(new SimpleGrantedAuthority(role)));
        permissions.forEach(per -> authorities.add(new SimpleGrantedAuthority(per)));
        LoginUser loginUser = new LoginUser(user, authorities);
        String jsonString = JSON.toJSONString(loginUser);
        loginUser.setToken(JwtUtils.sign(jsonString));
        // 底层会自动将 查询出来的 loginUser中的密码 和 前端获取的密码进行校验
        loginUser.setPassword(user.getPassword());
        return loginUser;
    }
}
